import java.io.*;
import java.util.*;
import java.lang.*;
import java.text.SimpleDateFormat;

public class Balancer {
	
	/**
	*
	*/
	
	private static Vector<Server> serverList;
	private static Constant constant;
	
	public Balancer() {
		serverList = new Vector<Server>();
		constant = new Constant();
	}
	
	//	Runs new virtual machine instance.
	//	Function used: euca-run-instances
	public static boolean runInstance() {
		String path = "/var/lib/eucalyptus/LSS/commands/";
		try {
			Process process = Runtime.getRuntime().exec(path + "run-instance");
			try { 
				process.waitFor();
			}
			catch(Exception e) {
				writeLog(e.getMessage());
			}
			BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
			String processResponse;
			int line = 0;
			//	Get string returned by euca-run-instances.
			while((processResponse = bufferedReader.readLine()) != null) {
				if(++line == 2) {
					//	Line 2: INSTANCE <Instance ID> <Image iD> <Private IP> <Public IP> <State> <Key> ...
					String instance[] = processResponse.split("	");
					serverList.addElement(new Server(instance[constant.id].trim(), instance[constant.image].trim(), instance[constant.privateIP].trim(), instance[constant.publicIP].trim(), instance[constant.state].trim(), instance[constant.key].trim(), instance[constant.type].trim()));
					return true;
				}
			}
		}
		catch(Exception e) {
			writeLog(e.getMessage());
		}
		return false;
	}
	//	Returns current state of the Balancer instance.
	//	Possible return values: 0, 1, 2
	public static int getState() {
		if(serverList.isEmpty()) return constant.inactive;
		
		int n = serverList.size();
		for(int i = 0; i < n; i++) {
			if(serverList.get(i).getState().equals("running")) return constant.active;
		}
		//	If serverList is not empty and none of the instantiated servers is on 'running' state:
		return constant.waiting;
	}
	public static String getDestination() {
		int n = serverList.size();
		int index = -1;
		double min = 1.0;
		for(int i = 0; i < n; i++) {
			Server server = serverList.get(i);
			if(server.getState().equals("running") && server.getLoad() < min) {
				index = i;
				min = server.getLoad();
				
				if(min == 0) break;
			}
		}
		if(index >= 0) return serverList.get(index).getInstanceID();
		return null;
	}
	public static String getServerPublicIP(String instanceID) {
		int n = serverList.size();
		for(int i = 0; i < n; i++) {
			Server server = serverList.get(i);
			if(server.getInstanceID().equals(instanceID)) {
				return server.getPublicIP();
			}
		}
		return null;
	}
	//	Updates state of each Server instance included in serverList.
	//	Function used: Server.updateState()
	public static void updateServerState() {
		int n = serverList.size();
		for(int i = 0; i < n; i++) {
			serverList.get(i).updateState();
		}
	}
	public static void updateServerLoad(double requirement, String instanceID) {
		int n = serverList.size();
		for(int i = 0; i < n; i++) {
			Server server = serverList.get(i);
			if(server.getInstanceID().equals(instanceID)) {
				server.updateLoad(requirement);
				break;
			}
		}
	}
	/**
	*	Private methods for class Balancer:
	*/
	
	private static void writeLog(String msg) {
		String path = "/var/lib/eucalyptus/LSS/logs/";
		Calendar calendar = Calendar.getInstance();
		SimpleDateFormat simpleDateFormat = new SimpleDateFormat("ddMMMyyyy");
		String filename = path + "balancer." + simpleDateFormat.format(calendar.getTime()) + ".log";
		//	Sample filename: balancer.14Mar2012.log
		try {
			FileWriter fileWriter = new FileWriter(filename, true);
			BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
			bufferedWriter.write(msg + "\n");
			bufferedWriter.close();
		}
		catch (Exception e) {
			System.err.println(e);
		}
	}
	
}

class Constant {
	
	/**
	*
	*/
	
	public static final int id = 1;
	public static final int image = 2;
	public static final int privateIP = 3;
	public static final int publicIP = 4;
	public static final int state = 5;
	public static final int key = 6;
	public static final int type = 8;
	
	public static final int inactive = 0;
	public static final int waiting = 1;
	public static final int active = 2;
	
	public Constant() {
	}

}